package org.javaforever.gatescore.core;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.javaforever.gatescore.complexverb.FrontTwinsVerb;
import org.javaforever.gatescore.exception.ValidateException;
import org.javaforever.gatescore.generators.PackageJsonGenerator;
import org.javaforever.gatescore.reports.LayoutComb;
import org.javaforever.gatescore.reports.ReportComb;
import org.javaforever.gatescore.shiroauth.ShiroAuthModule;
import org.javaforever.gatescore.shiroauth.vue.PermissionJSGenerator;
import org.javaforever.gatescore.utils.StringUtil;
import org.javaforever.gatescore.vue.DevEnvJs;
import org.javaforever.gatescore.vue.ElementUIHomePage;
import org.javaforever.gatescore.vue.EnJs;
import org.javaforever.gatescore.vue.NavbarVue;
import org.javaforever.gatescore.vue.ProdEnvJs;
import org.javaforever.gatescore.vue.SitEnvJs;
import org.javaforever.gatescore.vue.VueIndexRouterGenerator;
import org.javaforever.gatescore.vue.VuePageVars;
import org.javaforever.gatescore.vue.VueRouter;
import org.javaforever.gatescore.vue.ZhJs;

public class FrontProject implements Comparable<FrontProject>,Cloneable,Serializable  {
	private static final long serialVersionUID = -7116108379537547563L;
	protected String standardName;
	protected String technicalstack;
	protected String folderPath = "/home/jerry/JerryWork/GatesCore/TestBed/source/";
	protected String templatesPath = "/home/jerry/git/GatesCore/GatesCore/templates/";
	protected List<FrontPrism> prisms = new ArrayList<FrontPrism>();
	protected Set<FrontUtil> utils = new TreeSet<FrontUtil>();
	protected Set<FrontConfigFile> configFiles = new TreeSet<FrontConfigFile>();
	protected List<FrontDomain> domains = new ArrayList<FrontDomain>();
	protected String sgsSource;
	protected String sqlSource;
	protected String label;
	protected String excelTemplateName = "";
	protected String excelTemplateFolder = "";
	protected String title = "";
	protected String subTitle = "";
	protected String footer = "";
	protected String frontBaseApi = "";
	protected List<ReportComb> reportCombs = new ArrayList<>();
	protected List<LayoutComb> layoutCombs = new ArrayList<>();
	protected String backendProjectName = "";
	protected boolean showBackendProject = false;
	protected boolean useController = false;
	protected boolean useControllerPrefix = false;
	
	protected String controllerSuffix="controller";
	protected String controllerNamingSuffix = "Controller";
	protected String language = "chinese";
	protected String projectHome = "";
	protected String dbType = "MariaDB";
	protected String computerLanguage = "java";
	protected String originalExcelTemplateName;
	protected Set<org.javaforever.gatescore.core.Module> modules = new TreeSet<>();
	protected String frontendUi = "vueElNode21";
	protected String backendUi = "easyUi";
	protected PackageJsonGenerator pjg;
	protected boolean useOnlyJson = false;	
	
	public boolean isUseOnlyJson() {
		return useOnlyJson;
	}

	public void setUseOnlyJson(boolean useOnlyJson) {
		this.useOnlyJson = useOnlyJson;
	}

	public String getOriginalExcelTemplateName() {
		return originalExcelTemplateName;
	}

	public void setOriginalExcelTemplateName(String originalExcelTemplateName) {
		this.originalExcelTemplateName = originalExcelTemplateName;
	}
	
	public boolean isUseController() {
		return useController;
	}

	public void setUseController(boolean useController) {
		this.useController = useController;
	}

	@Override
	public int compareTo(FrontProject o) {
		return this.standardName.compareTo(o.getStandardName());
	}
	
	public ValidateInfo validate() {
		ValidateInfo info = new ValidateInfo();
		info.setSuccess(true);
		return info;
	}
	
	public void decorateMentuItems() {
		
	}
	
	public Set<FrontManyToMany> getMtms(){
		Set<FrontManyToMany> mtms = new TreeSet<>();
		for (FrontPrism fp:this.getPrisms()) {
			Set<FrontManyToMany> cmtms = fp.getManyToManies();
			if (cmtms !=null&& cmtms.size()>0) mtms.addAll(cmtms);
		}
		return mtms;
	}
	
	public void decorateUserControllers() {
		boolean useController = this.isUseController();
		for (FrontPrism fp: this.prisms) {
			fp.getDomain().setUseController(useController);
			for (FrontManyToMany fmtm:fp.getManyToManies()) {
				fmtm.getMaster().setUseController(useController);
				fmtm.getSlave().setUseController(useController);
			}
			for (FrontTwinsVerb ftv: fp.getTwinsverbs()) {
				ftv.getMaster().setUseController(useController);
			}
		}
	}
	
	public  void writeToFile(String filePath, String content) throws Exception{
		File f = new File(filePath);
		if (!f.getParentFile().exists()) {
			f.getParentFile().mkdirs();
		}
		f.createNewFile();
		try (Writer fw = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(f.getAbsolutePath()),"UTF-8"))){			
	        fw.write(content,0,content.length());
		}
	}
	
	public void generateProjectFiles(String exportStr) throws Exception {
		List<String> exports = new ArrayList<>();
		if (StringUtil.isBlank(exportStr)) exportStr = "";
		String [] exportArr = exportStr.split(",");
		for (String str :exportArr) {
			exports.add(str);
		}
		ValidateInfo info = this.validate();
		if (info.success(false) == false) {
			throw new ValidateException(info);
		}
		decorateMentuItems();
		decorateUserControllers();
		String srcfolderPath = this.getFolderPath()+this.standardName+"/";
		if (this.getSgsSource() != null && !this.getSgsSource().equals("")) {
			writeToFile(srcfolderPath + "sgs/" + StringUtil.capFirst(this.getStandardName()) + "_original.sgs",
					this.getSgsSource());
		}
		
		File templatesfrom = new File(this.getTemplatesPath() + "FrontEndTemplates/");
		File templatesto = new File(srcfolderPath);
		
		FileCopyer copy = new FileCopyer();
		
		copyExcelTemplates(srcfolderPath);
		
		// 设置来源去向
		copy.dirFrom = templatesfrom;
		copy.dirTo = templatesto;
		copy.listFileInDir(templatesfrom);
		
		EnJs enjs = new EnJs();
		enjs.setStanadardName(this.standardName);
		writeToFile(srcfolderPath + "src/lang/en.js",
				enjs.generateStatementList().getContent());
		
		ZhJs zhjs = new ZhJs();
		zhjs.setStanadardName(this.standardName);
		writeToFile(srcfolderPath + "src/lang/zh.js",
				zhjs.generateStatementList().getContent());

		writeToFile(srcfolderPath + this.pjg.getFileName(),
				this.pjg.generateString());
		
		for (org.javaforever.gatescore.core.Module m:this.getModules()) {
			if (m instanceof ShiroAuthModule) {
				PermissionJSGenerator permg = new PermissionJSGenerator();
				permg.setShiroAuthModule((ShiroAuthModule)m);
				permg.setDomains(this.getDomains());
				List<FrontManyToMany> mtms = new ArrayList<>();
				mtms.addAll(this.getMtms());
				permg.setMtms(mtms);
				permg.setLayouts(this.getLayoutCombs());
				permg.setReports(this.getReportCombs());
				writeToFile(srcfolderPath + "src/store/modules/" + permg.getFileName(),
						permg.generateStatementList().getContent());
			}		
		}
		
		NavbarVue nav = new NavbarVue();
		nav.setProjectHome(this.getProjectHome());
		writeToFile(srcfolderPath + "src/views/layout/components/Navbar.vue",
				nav.generateStatementList().getContent());
		
		DevEnvJs devenvjs = new DevEnvJs();
		devenvjs.setUseController(this.isUseController());
		devenvjs.setUseControllerPrefix(this.isUseControllerPrefix());
		devenvjs.setControllerPackageSuffix(this.getControllerSuffix());
		devenvjs.setFrontBaseApi(this.getFrontBaseApi());
		devenvjs.setShowBackendProject(this.showBackendProject);
		devenvjs.setBackendProjectName(this.backendProjectName);
		devenvjs.setTechnicalStack(this.technicalstack);
		writeToFile(srcfolderPath + "config/"+devenvjs.getFileName(),
				devenvjs.generateStatementList().getContent());
		
		String [] controllerPackageSuffixs = this.getControllerSuffix().split(".");
		String  controllerPackageSuffix = "controller";
		if (controllerPackageSuffixs.length >= 1) controllerPackageSuffix = controllerPackageSuffixs[controllerPackageSuffixs.length-1];
		SitEnvJs sitenvjs = new SitEnvJs();
		sitenvjs.setUseController(this.isUseController());
		sitenvjs.setUseControllerPrefix(this.isUseControllerPrefix());
		sitenvjs.setControllerPackageSuffix(this.getControllerSuffix());
		sitenvjs.setFrontBaseApi(this.getFrontBaseApi());
		sitenvjs.setShowBackendProject(this.showBackendProject);
		sitenvjs.setBackendProjectName(this.backendProjectName);
		sitenvjs.setControllerPackageSuffix(controllerPackageSuffix);
		sitenvjs.setTechnicalStack(this.technicalstack);
		writeToFile(srcfolderPath + "config/"+sitenvjs.getFileName(),
				sitenvjs.generateStatementList().getContent());
		
		ProdEnvJs prodenvjs = new ProdEnvJs();
		prodenvjs.setUseController(this.isUseController());
		prodenvjs.setUseControllerPrefix(this.isUseControllerPrefix());
		prodenvjs.setControllerPackageSuffix(this.getControllerSuffix());
		prodenvjs.setFrontBaseApi(this.getFrontBaseApi());
		prodenvjs.setShowBackendProject(this.showBackendProject);
		prodenvjs.setBackendProjectName(this.backendProjectName);
		prodenvjs.setControllerPackageSuffix(controllerPackageSuffix);
		prodenvjs.setTechnicalStack(this.technicalstack);
		writeToFile(srcfolderPath + "config/"+prodenvjs.getFileName(),
				prodenvjs.generateStatementList().getContent());
		
		ElementUIHomePage hpage = new ElementUIHomePage();
		hpage.setLanguage(this.getLanguage());
		writeToFile(srcfolderPath + "src/views/pages/index.vue",
				hpage.generateStatementList().getContent());
		for (FrontPrism ps : this.prisms) {
			if (StringUtil.isBlank(exportStr) || exports.contains(ps.getDomain().getStandardName())){
				ps.setFolderPath(srcfolderPath);
				if (!filterFrontPrism(ps)) ps.generatePrismFiles();
			}
		}
		
		for (org.javaforever.gatescore.core.Module m : this.modules) {
			if (StringUtil.isBlank(exportStr) || exports.contains(m.getStandardName())){
				ShiroAuthModule sam = (ShiroAuthModule) m;
				sam.generateModuleFiles(srcfolderPath);
			}
		}
		
		for (ReportComb rcb : this.reportCombs) {
			if (StringUtil.isBlank(exportStr) || exports.contains(rcb.getStandardName())){
				rcb.generateCombFiles(srcfolderPath);
			}
		}
		
		for (LayoutComb lcb : this.layoutCombs) {
			if (StringUtil.isBlank(exportStr) || exports.contains(lcb.getStandardName())){
				lcb.generateCombFiles(srcfolderPath);
			}
		}
		
		VuePageVars pv = new VuePageVars();
		pv.setDomains(this.getDomains());
		if (this.getModules()!=null &&this.getModules().size()>0) {
			for (org.javaforever.gatescore.core.Module m:this.getModules()) {
				ShiroAuthModule sam = (ShiroAuthModule)m;
				pv.setUserDomain(sam.getUserDomain());
			}
		}
		writeToFile(srcfolderPath +"src/" +pv.getFileName(),
				pv.generateStatementList().getContent());
		
		VueIndexRouterGenerator virg = new VueIndexRouterGenerator();
		virg.setHasAuth(this.containsAuth());
		writeToFile(srcfolderPath + "src/router/"+virg.getFileName(),
				virg.generateStatementList().getContent());
		
		VueRouter vr = new VueRouter();
		vr.setDomains(this.domains);
		if (this.containsAuth()) {
			for (org.javaforever.gatescore.core.Module m:this.getModules()) {
				ShiroAuthModule sam = (ShiroAuthModule)m;
				vr.setUserDomain(sam.getUserDomain());
			}
		}
		for (FrontPrism fp:this.prisms) {
			vr.addMtms(fp.getManyToManies());
		}
		vr.setReportCombs(this.getReportCombs());
		vr.setLayoutCombs(this.getLayoutCombs());
		writeToFile(srcfolderPath + "src/router/modules/"+vr.getFileName(),
				vr.generateStatementList().getContent());
	}
	
	public static boolean delAllFile(String path) {
		boolean flag = false;
		File file = new File(path);
		if (!file.exists()) {
			return flag;
		}
		if (!file.isDirectory()) {
			return flag;
		}
		String[] tempList = file.list();
		File temp = null;
		if (tempList != null) {
			for (int i = 0; i < tempList.length; i++) {
				if (path.endsWith(File.separator)) {
					temp = new File(path + tempList[i]);
				} else {
					temp = new File(path + File.separator + tempList[i]);
				}
				if (temp.isFile()) {
					temp.delete();
				}
				if (temp.isDirectory()) {
					delAllFile(path + "/" + tempList[i]);// 先删除文件夹里面的文件
					delFolder(path + "/" + tempList[i]);// 再删除空文件夹
					flag = true;
				}
			}
		}
		return flag;
	}

	
	public static void delFolder(String folderPath) {
		try {
			delAllFile(folderPath); // 删除完里面所有内容
			String filePath = folderPath;
			filePath = filePath.toString();
			java.io.File myFilePath = new java.io.File(filePath);
			myFilePath.delete(); // 删除空文件夹
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void generateProjectZip(String exportStr) throws Exception{
		delAllFile(this.folderPath+this.standardName+".zip");
		delFolder(this.getFolderPath()+this.standardName+"/");
		File f = new File(this.getFolderPath());
		if (!f.getParentFile().exists()) {
			f.getParentFile().mkdirs();
		}
		f.mkdirs();
				
		generateProjectFiles(exportStr);
		ZipCompressor compressor = new ZipCompressor(this.folderPath+this.standardName+".zip");
		compressor.compressExe(this.getFolderPath()+this.standardName+"/");
		delFolder(this.getFolderPath()+this.standardName+"/");
	}
	
	public String getStandardName() {
		return standardName;
	}
	public void setStandardName(String standardName) {
		this.standardName = standardName;
	}
	public String getTechnicalstack() {
		return technicalstack;
	}
	public void setTechnicalstack(String technicalstack) {
		this.technicalstack = technicalstack;
	}
	public String getFolderPath() {
		return folderPath;
	}
	public Set<FrontUtil> getUtils() {
		return utils;
	}
	public void setUtils(Set<FrontUtil> utils) {
		this.utils = utils;
	}
	public Set<FrontConfigFile> getConfigFiles() {
		return configFiles;
	}
	public void setConfigFiles(Set<FrontConfigFile> configFiles) {
		this.configFiles = configFiles;
	}
	public String getSgsSource() {
		return sgsSource;
	}
	public void setSgsSource(String sgsSource) {
		this.sgsSource = sgsSource;
	}
	public String getSqlSource() {
		return sqlSource;
	}
	public void setSqlSource(String sqlSource) {
		this.sqlSource = sqlSource;
	}
	public String getLabel() {
		return label;
	}
	public void setLabel(String label) {
		this.label = label;
	}
	public String getExcelTemplateName() {
		return excelTemplateName;
	}
	public void setExcelTemplateName(String excelTemplateName) {
		this.excelTemplateName = excelTemplateName;
	}
	public String getExcelTemplateFolder() {
		return excelTemplateFolder;
	}
	public void setExcelTemplateFolder(String excelTemplateFolder) {
		this.excelTemplateFolder = excelTemplateFolder;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getSubTitle() {
		return subTitle;
	}
	public void setSubTitle(String subTitle) {
		this.subTitle = subTitle;
	}
	public String getFooter() {
		return footer;
	}
	public void setFooter(String footer) {
		this.footer = footer;
	}

	public String getTemplatesPath() {
		return templatesPath;
	}

	public void setTemplatesPath(String templatesPath) {
		this.templatesPath = templatesPath;
	}

	public String getBackendProjectName() {
		return backendProjectName;
	}

	public void setBackendProjectName(String backendProjectName) {
		this.backendProjectName = backendProjectName;
	}

	public boolean isShowBackendProject() {
		return showBackendProject;
	}

	public void setShowBackendProject(boolean showBackendProject) {
		this.showBackendProject = showBackendProject;
	}

	public void putAllDomains(List<FrontDomain> domainList) {
		this.domains.clear();
		this.domains.addAll(domainList);		
	}

	/**
	 * 
	 * 从JAR中复制文件到磁盘	 * 
	 * @param srcFilePath：源路径，既JAR包中的资源文件，路径相对于CLASSPATH 
	 * @param destFilePath：目标路径，磁盘上的任意路径，绝对路径（一般为用户选择的文件夹路径）
	 * @return int：返回执行后的状态；0：失败；1：成功；（可以扩充其它状态）
	 * 
	 */

	public static int fileCopy(String srcFilePath, String destFilePath) {
		int flag = 0;
		File destFile = new File(destFilePath);

		try {
			BufferedInputStream fis = new BufferedInputStream(ClassLoader.getSystemResourceAsStream(srcFilePath));
			FileOutputStream fos = new FileOutputStream(destFile);
			byte[] buf = new byte[1024];
			int c = 0;
			while ((c = fis.read(buf)) != -1) {
				fos.write(buf, 0, c);
			}

			fis.close();

			fos.close();

			flag = 1;

		} catch (IOException e) {

			e.printStackTrace();

		}

		return flag;

	}

	public String getControllerSuffix() {
		return controllerSuffix;
	}

	public void setControllerSuffix(String controllerSuffix) {
		this.controllerSuffix = controllerSuffix;
	}

	public String getControllerNamingSuffix() {
		return controllerNamingSuffix;
	}

	public void setControllerNamingSuffix(String controllerNamingSuffix) {
		this.controllerNamingSuffix = controllerNamingSuffix;
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	public String getFrontBaseApi() {
		return frontBaseApi;
	}

	public void setFrontBaseApi(String frontBaseApi) {
		this.frontBaseApi = frontBaseApi;
	}

	public boolean isUseControllerPrefix() {
		return useControllerPrefix;
	}

	public void setUseControllerPrefix(boolean useControllerPrefix) {
		this.useControllerPrefix = useControllerPrefix;
	}

	public Set<org.javaforever.gatescore.core.Module> getModules() {
		return modules;
	}

	public void setModules(Set<org.javaforever.gatescore.core.Module> modules) {
		this.modules = modules;
	}

	public void addModule(org.javaforever.gatescore.core.Module m) {
		this.modules.add(m);
	}

	public List<FrontPrism> getPrisms() {
		return prisms;
	}

	public void setPrisms(List<FrontPrism> prisms) {
		this.prisms = prisms;
	}

	public List<FrontDomain> getDomains() {
		return domains;
	}

	public void setDomains(List<FrontDomain> domains) {
		this.domains = domains;
	}

	public void setFolderPath(String folderPath) {
		this.folderPath = folderPath;
	}
	
	public boolean filterFrontPrism(FrontPrism fprism) {
		for (org.javaforever.gatescore.core.Module m : this.getModules()) {
			if ("ShiroAuth".equalsIgnoreCase(m.getStandardName())||"SimpleAuth".equalsIgnoreCase(m.getStandardName())) {
				ShiroAuthModule sam = (ShiroAuthModule) m;
				if (fprism.getDomain().getStandardName().equals(sam.getUserDomain().getStandardName())) {
					return true;
				} 
			}
		}
		return false;
	}

	public List<ReportComb> getReportCombs() {
		return reportCombs;
	}

	public void setReportCombs(List<ReportComb> reportCombs) {
		this.reportCombs = reportCombs;
	}
	
	public void addReportComb(ReportComb reportComb) {
		this.reportCombs.add(reportComb);
	}

	public List<LayoutComb> getLayoutCombs() {
		return layoutCombs;
	}

	public void setLayoutCombs(List<LayoutComb> layoutCombs) {
		this.layoutCombs = layoutCombs;
	}
	
	public void addLayoutComb(LayoutComb layoutComb) {
		this.layoutCombs.add(layoutComb);
	}

	public boolean containsAuth() {
		if (this.getModules()!=null&& this.getModules().size()>0) {
			for ( org.javaforever.gatescore.core.Module m:this.getModules()) {
				if (m.getStandardName().equalsIgnoreCase("SimpleAuth")||m.getStandardName().equalsIgnoreCase("ShiroAuth")) return true;
			}
		}
		return false;
	}

	public String getProjectHome() {
		return projectHome;
	}

	public void setProjectHome(String projectHome) {
		this.projectHome = projectHome;
	}

	public String getDbType() {
		return dbType;
	}

	public void setDbType(String dbType) {
		this.dbType = dbType;
	}

	public String getComputerLanguage() {
		return computerLanguage;
	}

	public void setComputerLanguage(String computerLanguage) {
		this.computerLanguage = computerLanguage;
	}
	
	public void copyExcelTemplates(String srcfolderPath) throws Exception{
		FileCopyer copy = new FileCopyer();
		if (!StringUtil.isBlank(this.getExcelTemplateName())) {
			File mF1 = new File(
					(this.getExcelTemplateFolder() + this.getExcelTemplateName()).replace("\\", "/"));
			File mF2 = new File(
					(srcfolderPath + "exceltemplate/" + this.getExcelTemplateName())
							.replace("\\", "/"));
			if (mF1.exists()) {
				if (!mF2.getParentFile().exists()) {
					mF2.getParentFile().mkdirs();
				}
				if (!mF2.exists()) {
					mF2.createNewFile();
				}
				copy.copy(mF1.getPath(), mF2.getPath());
			}
			if (!StringUtil.isBlank(this.getOriginalExcelTemplateName())) {
				File mF3 = new File(
						(this.getExcelTemplateFolder() + this.getOriginalExcelTemplateName()).replace("\\", "/"));
				File mF4 = new File(
						(srcfolderPath + "exceltemplate/" + this.getOriginalExcelTemplateName())
								.replace("\\", "/"));
				if (mF3.exists()) {
					if (!mF4.getParentFile().exists()) {
						mF4.getParentFile().mkdirs();
					}
					if (!mF4.exists()) {
						mF4.createNewFile();
					}
					copy.copy(mF3.getPath(), mF4.getPath());
				}
			}
		}
	}

	public String getFrontendUi() {
		return frontendUi;
	}

	public void setFrontendUi(String frontendUi) {
		this.frontendUi = frontendUi;
	}

	public String getBackendUi() {
		return backendUi;
	}

	public void setBackendUi(String backendUi) {
		this.backendUi = backendUi;
	}

	public PackageJsonGenerator getPjg() {
		return pjg;
	}

	public void setPjg(PackageJsonGenerator pjg) {
		this.pjg = pjg;
	}
}
